package cn.tianyigps.obd.utils;

import cn.tianyigps.obd.constant.Constant;
import io.netty.util.internal.StringUtil;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created with IDEA
 *
 * @description: M5B扩展字段
 * @author: cui.guibin
 * @create: 2019/4/1 17:56
 **/
public class ExtendUtil {

    public static Map<String,String> getAlarm(String substring) {
        Map<String,String> alarm = new HashMap<>();
        String binaryString = getBinaryString(substring);
        // 方案一
        // 低电压报警
        alarm.put("lowVoltage",String.valueOf(binaryString.charAt(4)));
        // 翻车报警
        alarm.put("rollover",String.valueOf(binaryString.charAt(5)));
        // 拖车报警
        alarm.put("trailer",String.valueOf(binaryString.charAt(6)));
        // 碰撞报警
        alarm.put("collision",String.valueOf(binaryString.charAt(7)));
        // 怠速过长报警（点火状态下，车辆发动机持续有转速，车速为0并持续至少10分钟）
        alarm.put("idleSpeed",String.valueOf(binaryString.charAt(10)));
        // 定位过长报警（连续5min未定位）
        alarm.put("longLoc",String.valueOf(binaryString.charAt(11)));
        // 车机插上报警（带电池情况下）
        alarm.put("machineIn",String.valueOf(binaryString.charAt(12)));
        // 车机拔出报警（带电池情况下）
        alarm.put("machineOut",String.valueOf(binaryString.charAt(13)));
        // 汽车熄火
        alarm.put("carStop",String.valueOf(binaryString.charAt(14)));
        // 汽车点火
        alarm.put("carStart",String.valueOf(binaryString.charAt(15)));
        // GID GPS模块故障报警
        alarm.put("gpsFault",String.valueOf(binaryString.charAt(20)));
        // GID 3D传感器故障报警
        alarm.put("3dFault",String.valueOf(binaryString.charAt(21)));
        // GID CAN模块故障报警
        alarm.put("canFault",String.valueOf(binaryString.charAt(22)));
        // GID FLASH故障报警
        alarm.put("flashFault",String.valueOf(binaryString.charAt(23)));

        // 方案二
//        for (int i = 0; i <binaryString.length() ; i++) {
//            String s = binaryString.substring(i, i + 1);
//            if("1".equals(s)){
//                switch (i){
//                    case 4:// 低电压报警
//                        alarm.put("lowVoltage",s);
//                        break;
//                    case 5:// 翻车报警
//                        alarm.put("rollover",s);
//                        break;
//                    case 6: // 拖车报警
//                        alarm.put("trailer",s);
//                        break;
//                    case 7: // 碰撞报警
//                        alarm.put("collision",s);
//                        break;
//                    case 10: // 怠速过长报警（点火状态下，车辆发动机持续有转速，车速为0并持续至少10分钟）
//                        alarm.put("idleSpeed",s);
//                        break;
//                    case 11: //定位过长报警（连续5min未定位）
//                        alarm.put("longLoc",s);
//                        break;
//                    case 12: // 车机插上报警（带电池情况下）
//                        alarm.put("machineIn",s);
//                        break;
//                    case 13: // 车机拔出报警（带电池情况下）
//                        alarm.put("machineOut",s);
//                        break;
//                    case 14: //汽车熄火
//                        alarm.put("carStop",s);
//                        break;
//                    case 15:// 汽车点火
//                        alarm.put("carStart",s);
//                        break;
//                    case 20:// GID GPS模块故障报警
//                        alarm.put("gpsFault",s);
//                        break;
//                    case 21:// GID 3D传感器故障报警
//                        alarm.put("3dFault",s);
//                        break;
//                    case 22:// GID CAN模块故障报警
//                        alarm.put("canFault",s);
//                        break;
//                    case 23://GID FLASH故障报警
//                        alarm.put("flashFault",s);
//                        break;
//                }
//            }
//        }
        return alarm;
    }

    public static Map<String,String> getOBD(String substring) {
        Map<String,String> obd = new HashMap<>();
        String statusMask = substring.substring(0, 2);
        String statusBinaryString = getBinaryString(statusMask);
        obd.put("statusMask",statusBinaryString);
        // 将支持的数据放入list等待解析
        List<Integer> stausList = new ArrayList<>();
        for (int i = 0; i < statusBinaryString.length() ; i++) {
            if ('1' == statusBinaryString.charAt(i))
                stausList.add(i);
        }
        String dsMask = substring.substring(2, 12);
        String dsBinaryString = getBinaryString(dsMask);
        obd.put("dsMask",dsBinaryString);
        // 将支持的数据放入list等待解析
        List<Integer> dsList = new ArrayList<>();
        for (int i = 0; i < dsBinaryString.length() ; i++) {
            if ('1' == dsBinaryString.charAt(i))
                dsList.add(i);
        }
        String packNum = substring.substring(12, 14);
        obd.put("packNum",packNum);
        Integer count = 0;
        for (int i = 0; i < stausList.size(); i++) {
            Integer bit = stausList.get(i);
            Integer addNum = 2 * count;
            String subStr = substring.substring(14 + addNum,16 + addNum + 2);
            String subStrString = getBinaryString(subStr);
            if (StringUtil.isNullOrEmpty(subStrString))
                continue;
            switch (bit){
                case 0: // SECURITY STATUS
                    obd.put("acc",String.valueOf(subStrString.charAt(0)));
                    obd.put("fortification",String.valueOf(subStrString.charAt(1)));
                    count ++;
                    break;
                case 1: // Door Status
                    obd.put("lfDoor",String.valueOf(subStrString.charAt(0)));
                    obd.put("rfDoor",String.valueOf(subStrString.charAt(1)));
                    obd.put("lbDoor",String.valueOf(subStrString.charAt(2)));
                    obd.put("rbDoor",String.valueOf(subStrString.charAt(3)));
                    obd.put("trunkDoor",String.valueOf(subStrString.charAt(4)));
                    count ++;
                    break;
                case 2: // Window Status
                    obd.put("lfWindow",String.valueOf(subStrString.charAt(0)));
                    obd.put("rfWindow",String.valueOf(subStrString.charAt(1)));
                    obd.put("lbWindow",String.valueOf(subStrString.charAt(2)));
                    obd.put("rbWindow",String.valueOf(subStrString.charAt(3)));
                    count ++;
                    break;
                case 3: // LockStatus
                    obd.put("lfLock",String.valueOf(subStrString.charAt(0)));
                    obd.put("rfLock",String.valueOf(subStrString.charAt(1)));
                    obd.put("lbLock",String.valueOf(subStrString.charAt(2)));
                    obd.put("rbLock",String.valueOf(subStrString.charAt(3)));
                    obd.put("trunkLock",String.valueOf(subStrString.charAt(4)));
                    count ++;
                    break;
                default:
            }
        }
        for (int i = 0; i < dsList.size(); i++) {
            Integer addNum = 2 * count;
            Integer bit = dsList.get(i);
            switch (bit){

                case 0: // MalfunctionIndicator Lamp Status
                    String milStr = substring.substring(14 + addNum,14 + addNum + 2);
                    String milBinaryStr = getBinaryString(milStr);
                    obd.put("MIL",String.valueOf(milBinaryStr.charAt(7)));
                    count ++;
                    break;

                case 1: // DTCs stored in this ECU
                    String dtcNumStr = substring.substring(14 + addNum,14 + addNum + 2);
                    String num = StringAnalysisUtil.getDecimalString(dtcNumStr);
                    obd.put("dtcNum",num);
                    count ++;
                    break;

                case 2: // Vehicle Voltage
                    String voltageStr = substring.substring(14 + addNum,14 + addNum + 4);
                    String voltage = getVoltage(voltageStr);
                    obd.put("voltage",voltage);
                    count += 2;
                    break;

                case 3: // Engine RPM
                    String rpmStr = substring.substring(14 + addNum,14 + addNum + 4);
                    String engineRPM = StringAnalysisUtil.getDecimalString(rpmStr);
                    obd.put("engineRPM",engineRPM);
                    count += 2;
                    break;

                case 4: // Vehicle Speed
                    String speedStr = substring.substring(14 + addNum,14 + addNum + 2);
                    String speed = StringAnalysisUtil.getDecimalString(speedStr);
                    obd.put("speed",speed);
                    count ++;
                    break;

                case 5: // Intake Air temperature
                    String intakeAirTempStr = substring.substring(14 + addNum,14 + addNum + 2);
                    Integer intakeAirTemp = Integer.parseInt(StringAnalysisUtil.getDecimalString(intakeAirTempStr)) - 40;
                    obd.put("intakeAirTemp",intakeAirTemp.toString());
                    count ++;
                    break;

                case 6: // EngineCoolant Temperature
                    String coolantTempStr = substring.substring(14 + addNum,14 + addNum + 2);
                    Integer coolantTemp = Integer.parseInt(StringAnalysisUtil.getDecimalString(coolantTempStr)) - 40;
                    obd.put("coolantTemp",coolantTemp.toString());
                    count ++;
                    break;

                case 7: // Environment Temperature
                    String envTempStr = substring.substring(14 + addNum,14 + addNum + 2);
                    Integer envTemp = Integer.parseInt(StringAnalysisUtil.getDecimalString(envTempStr)) - 40;
                    obd.put("envTemp",envTemp.toString());
                    count ++;
                    break;

                case 8: // Intake Manifold Pressure  kpa
                    String intakePressStr = substring.substring(14 + addNum,14 + addNum + 2);
                    String intakePress = StringAnalysisUtil.getDecimalString(intakePressStr);
                    obd.put("intakePressure",intakePress);
                    count ++;
                    break;

                case 9: // Fuel Pressure
                    String fuelPressureStr = substring.substring(14 + addNum,14 + addNum + 4);
                    String fuelPressure = StringAnalysisUtil.getDecimalString(fuelPressureStr);
                    obd.put("fuelPressure",fuelPressure);
                    count += 2;
                    break;

                case 10:// Barometric Pressure
                    String barometricPressureStr = substring.substring(14 + addNum,14 + addNum + 2);
                    String barometricPressure = StringAnalysisUtil.getDecimalString(barometricPressureStr);
                    obd.put("barometricPressure",barometricPressure);
                    count ++;
                    break;

                case 11: // Air Flow Sensor
                    String airFlowSensorStr = substring.substring(14 + addNum,14 + addNum + 4);
                    String airFlowSensor = multiplyBy(airFlowSensorStr,10.0);
                    obd.put("airFlowSensor",airFlowSensor);
                    count += 2;
                    break;

                case 12: // Throttle Position Sensor
                    String throttlePositionSensorStr = substring.substring(14 + addNum,14 + addNum + 4);
                    String throttlePositionSensor = multiplyBy(throttlePositionSensorStr,10.0);
                    obd.put("throttlePositionSensor",throttlePositionSensor);
                    count += 2;
                    break;

                case 13: // Accelerator pedal position
                    String gasPedalPositionStr = substring.substring(14 + addNum,14 + addNum + 4);
                    String gasPedalPosition = multiplyBy(gasPedalPositionStr,10.0);
                    obd.put("gasPedalPosition",gasPedalPosition);
                    count += 2;
                    break;

                case 14:// Engine Run Time
                    String  engineRunTimeStr = substring.substring(14 + addNum,14 + addNum + 4);
                    String engineRunTime = StringAnalysisUtil.getDecimalString(engineRunTimeStr);
                    obd.put("engineRunTime",engineRunTime);
                    count += 2;
                    break;

                case 15:// Fault Vehicle Mileage   km
                    String  faultMileageStr = substring.substring(14 + addNum,14 + addNum + 8);
                    String faultMileage = StringAnalysisUtil.getDecimalString(faultMileageStr);
                    obd.put("faultMileage",faultMileage);
                    count += 4;
                    break;

                case 16:// Fuel Level
                    String  fuelLevelStr = substring.substring(14 + addNum,14 + addNum + 4);
                    String fuelLevel = multiplyBy(fuelLevelStr,10.0);
                    obd.put("fuelLevel",fuelLevel);
                    count += 2;
                    break;

                case 17:// Calculated Engine load
                    String  engineLoadStr = substring.substring(14 + addNum,14 + addNum + 2);
                    String engineLoad = StringAnalysisUtil.getDecimalString(engineLoadStr);
                    obd.put("engineLoad",engineLoad);
                    count ++;
                    break;

                case 18://Long Term Fuel Trim –Bank 1
                    String  longTermFuelTrimStr = substring.substring(14 + addNum,14 + addNum + 4);
                    String longTermFuelTrim = multiplyBy(longTermFuelTrimStr,10.0);
                    obd.put("longTermFuelTrim",longTermFuelTrim);
                    count += 2;
                    break;

                case 19://Spark Angle before TDC
                    String  angleBeforeTDCStr = substring.substring(14 + addNum,14 + addNum + 4);
                    String angleBeforeTDC = multiplyBy(angleBeforeTDCStr,10.0);
                    angleBeforeTDC = ((Double)(Double.valueOf(angleBeforeTDC) - 64.0)).toString();
                    obd.put("angleBeforeTDC",angleBeforeTDC);
                    count += 2;
                    break;

                case 37://Mileage&Fuel Flag
                    String  mileageTypeStr = substring.substring(14 + addNum,14 + addNum + 2);
                    String mileageType = StringAnalysisUtil.getDecimalString(mileageTypeStr);
                    obd.put("mileageType",mileageType);
                    count ++ ;
                    break;

                case 38://Total Mileage
                    String  totalMileageStr = substring.substring(14 + addNum,14 + addNum + 8);
                    String totalMileage = multiplyBy(totalMileageStr,1000.0);
                    obd.put("totalMileage",totalMileage);
                    count += 4;
                    break;

                case 39://Total Fuel Consumption
                    String  totalFuelConsumptionStr = substring.substring(14 + addNum,14 + addNum + 8);
                    String totalFuelConsumption = multiplyBy(totalFuelConsumptionStr,1000.0);
                    obd.put("totalFuelConsumption",totalFuelConsumption);
                    count += 4;
                    break;

                default:
            }
        }
        return obd;
    }

    public static Map<String,String> getFault(String substring) {

        Map<String,String> fault = new HashMap<>();
        String dtcs = "";
        String substring1 = substring.substring(0, 2);
        long dtcNum = StringAnalysisUtil.getDecimalLong(substring1);

        for (int i = 0; i < dtcNum; i++) {
            String dtc = substring.substring(2 + i * 10, 2 + (i + 1) * 10);
            dtc = StringAnalysisUtil.convertHexToStringByGB2312(dtc).trim();
            if (i == 0)
                dtcs += (dtc);
            else
                dtcs += (dtc + ",");
        }

        fault.put("dtc",dtcs);
        return fault;
    }

    public static Map<String,String> getCarInfo(String substring) {

        Map<String,String> carInfo = new HashMap<>();
        String brand = substring.substring(0, 2);
        carInfo.put("brand",brand);
        String product = substring.substring(2, 4);

        carInfo.put("product",product);
        String year = substring.substring(4, 6);
        carInfo.put("year",year);
        String gearType = substring.substring(6, 8);

        carInfo.put("gearType",gearType);
        String handleType = substring.substring(8, 10);
        carInfo.put("handleType",handleType);
        String obdProtocol = substring.substring(10, 12);

        carInfo.put("obdProtocol",obdProtocol);
        String vin = substring.substring(12, 46);
        carInfo.put("vin",StringAnalysisUtil.convertHexToStringByGB2312(vin));
        String engineDisplacement = substring.substring(46, 50);

        carInfo.put("engineDisplacement",engineDisplacement);
        String cidNum = substring.substring(50, 52);
        carInfo.put("cidNum",cidNum);
        Long decimalLong = StringAnalysisUtil.getDecimalLong(cidNum);

        String cids = "";
        for (int i = 0; i < decimalLong ; i++) {
            String cid = substring.substring(52 + i * 10, 52 + (i + 1) * 10);
            cid = StringAnalysisUtil.convertHexToStringByGB2312(cid).trim();
            if (i == 0)
                cids += (cid);
            else
                cids += (cid + ",");
        }

        carInfo.put("cids",cids);
        return carInfo;
    }

    public static Map<String,String> getVersionInfo(String substring) {

        Map<String,String> versionInfo = new HashMap<>();
        String swVersion = substring.substring(0, 24);
        versionInfo.put("swVersion",StringAnalysisUtil.convertHexToStringByGB2312(swVersion).trim());
        String swDate = substring.substring(24, 44);

        versionInfo.put("swDate",StringAnalysisUtil.convertHexToStringByGB2312(swDate).trim());
        String hwVersion = substring.substring(44, 60);
        versionInfo.put("hwVersion",StringAnalysisUtil.convertHexToStringByGB2312(hwVersion).trim());
        String comType = substring.substring(60, 76);

        versionInfo.put("comType",StringAnalysisUtil.convertHexToStringByGB2312(comType).trim());
        String bootLoaderVersion = substring.substring(76, 92);
        versionInfo.put("bootLoaderVersion",StringAnalysisUtil.convertHexToStringByGB2312(bootLoaderVersion).trim());
        String imsi = substring.substring(92, 122);

        versionInfo.put("imsi",StringAnalysisUtil.convertHexToStringByGB2312(imsi).trim());
        String iccid = substring.substring(122, 162);
        versionInfo.put("iccid",StringAnalysisUtil.convertHexToStringByGB2312(iccid).trim());
        String simNum = substring.substring(162, 202);

        versionInfo.put("simNum",StringAnalysisUtil.convertHexToStringByGB2312(simNum).trim());
        return versionInfo;
    }

    public static Map<String,String> getBase(String substring) {
        Map<String,String> base = new HashMap<>();
        String acc = substring.substring(0, 2);
        String accBinaryString = getBinaryString(acc);
        base.put("inputStatus",String.valueOf(accBinaryString.charAt(7)));
        String voltageStr = substring.substring(2, 6);
        String voltage = getVoltage(voltageStr);
        base.put("voltage",voltage);
        String mcc = substring.substring(6, 10);
        base.put("mcc",StringAnalysisUtil.getDecimalString(mcc));
        String mnc = substring.substring(10, 12);
        base.put("baseNum",StringAnalysisUtil.getDecimalString(substring.substring(12, 14)));
        base.put("mnc",mnc);
        if ("03".equals(mnc)){ // 03 电信 有 sid nid bid

        }else{ // 01 00 移动 联通 有 lac cellId
            base.put("lac",StringAnalysisUtil.getDecimalString(substring.substring(14, 18)));
            base.put("cellId",StringAnalysisUtil.getDecimalString(substring.substring(18, 24)));
        }

        return base;
    }

    /**
     * @param: str
     * @return string
     * @author cui.guibin
     * @date 2019/4/9 1:21
     * 单位 V
     */
    public static String getVoltage(String substring) {
        Integer ebLength = Integer.parseInt(StringAnalysisUtil.getDecimalString(substring));
        Double v = ebLength / 10.0;
        String vStr = v.toString();
        return vStr;
    }
    /**
     * @param: str
     * @return string
     * @author cui.guibin
     * @date 2019/4/9 1:21
     */
    public static String multiplyBy(String substring,Double d) {
        Long ebLength = StringAnalysisUtil.getDecimalLong(substring);
        Double divide = ebLength / d;
        String divideStr = divide.toString();
        return divideStr;
    }

    public static String getBinaryString(String str) {
        StringBuilder buffer = new StringBuilder();
        char[] chars = str.toCharArray();
        for (char c : chars) {
            String binStr = Integer.toBinaryString(Integer.parseInt(String.valueOf(c), Constant.INTEGER_SIXTEEN));
            //长度小于4时对数据进行补0
            if (binStr.length() < Constant.INTEGER_FOUR) {
                while (binStr.length() < Constant.INTEGER_FOUR) {
                    // sb.append(str).append(Constant.STRING_ZERO);//右补0
                    binStr = Constant.STRING_ZERO + binStr;// 左补0
                }
            }
            buffer.append(binStr);
        }
        return buffer.toString();
    }

}
